# Gupicasa's Albums editor
#
# Copyright (C) 2010 Yotam Medini <yotam.medini@gmail.com>
#
# This file is part of Gupicasa.
#
# Gupicasa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gupicasa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gupicasa.  If not, see <http://www.gnu.org/licenses/>.
#
# Using the EditableCellsDemo of Maik Hertha <maik.hertha@berlin.de>
# in pygtk demos.

import gobject
import gtk
import string

import debug
import ugtk

# columns
(
    COLUMN_NAME,
    COLUMN_SUMMARY,
    COLUMN_SIZE,
    COLUMN_EDITABLE,
    COLUMN_ID,
) = range(5)


class _ListEditor(gtk.Dialog):


    def __init__(self, parent):
        gtk.Dialog.__init__(self,
            title="Gupicasa - Albums Editor",
            parent=parent,
            flags=gtk.DIALOG_MODAL,
            buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
                     gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
        self.set_size_request(360, 400)
        vbox = self.vbox
        vbox.pack_start(gtk.Label("Select Picasa album"),
                        expand=False, fill=False, padding=6)

        self.scrolled_window = sw = gtk.ScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        vbox.pack_start(sw)

        model = gtk.ListStore(
            gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT,
            gobject.TYPE_BOOLEAN, gobject.TYPE_STRING)

        # create tree view
        self.treeview = treeview = gtk.TreeView(model)
        # treeview.set_rubber_banding(True)
        treeview.set_rules_hint(True)
        treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)

        self._add_columns(treeview)
        sw.add(treeview)

        hbox = self.create_buttons_box(treeview)
        vbox.pack_start(hbox, expand=False, fill=False, padding=6)

        self.statusbar = ugtk.SimpleStatusbar()
        self.statusbar.set_has_resize_grip(False)
        vbox.pack_end(self.statusbar, expand=False, fill=False, padding=2)
        self.show_all()


    def create_buttons_box(self, treeview):
        hbox = gtk.HBox(True, 12)
        button = self.button_new = gtk.Button(stock=gtk.STOCK_NEW)
        button.connect("clicked", self.new_cb, treeview)
        hbox.pack_start(button, padding=2)

        button = self.button_add = gtk.Button(stock=gtk.STOCK_ADD)
        button.connect("clicked", self.add_cb, treeview)
        button.set_sensitive(False)
        hbox.pack_start(button, padding=2)

        button = gtk.Button(stock=gtk.STOCK_REMOVE)
        button.connect("clicked", self.remove_cb, treeview)
        hbox.pack_start(button, padding=2)

        button = gtk.Button(stock=gtk.STOCK_REFRESH)
        button.connect("clicked", self.refresh_cb)
        hbox.pack_start(button, padding=2)

        return hbox


    def add_album(self, album_id, name, summary, n):
        # debug.log("album_id=%s, name=%s, summary=%s, n=%d" % 
        #          (album_id, name, summary, n))
        self.statusbar.set_text("Adding '%s' (%s) [%d] (id=%s)" % 
                                (name, summary, n, album_id))
        model = self.treeview.get_model()
        iter = model.append()
        model.set(iter,
                  COLUMN_NAME, name,
                  COLUMN_SUMMARY, summary,
                  COLUMN_SIZE, n,
                  COLUMN_EDITABLE, True,
                  COLUMN_ID, album_id)


    def select(self):
        debug.log("")
        album_id = None
        warn_msg = "Dummy warning"
        while warn_msg is not None:
            warn_msg = None
            response = self.run()
            debug.log("response=%d" % response)
            if response == gtk.RESPONSE_OK:
                selection = self.treeview.get_selection()
                model, iter = selection.get_selected()
                if iter:
                    album_id = model.get_value(iter, COLUMN_ID)
                button_add_active = self.button_add.get_property("sensitive")
                debug.log("add_active=%d" % button_add_active)
                if button_add_active:
                    warn_msg = "Newly entered album not added"
                elif album_id is None or album_id == "":
                    warn_msg = "No album selected"
                if warn_msg is not None:
                    ugtk.warning(self, warn_msg)
        debug.log("album_id=%s" % album_id)
        self.destroy()
        return album_id


    def _add_columns(self, treeview):

        model = treeview.get_model()
        columns = []

        # name column
        renderer = gtk.CellRendererText()
        renderer.connect("edited", self.cell_edited)
        renderer.connect("editing_started", self.editing_started)
        renderer.set_data("column", COLUMN_NAME)
        column = gtk.TreeViewColumn("Name", renderer, text=COLUMN_NAME,
                                    editable=COLUMN_EDITABLE)
        columns.append(column)

        # summary column
        renderer = gtk.CellRendererText()
        renderer.connect("edited", self.cell_edited)
        renderer.connect("editing_started", self.editing_started)
        renderer.set_data("column", COLUMN_SUMMARY)
        column = gtk.TreeViewColumn("Summary", renderer,
                                    text=COLUMN_SUMMARY,
                                    editable=COLUMN_EDITABLE)
        summary_column = column
        column.set_min_width(180);
        columns.append(column)

        # number of photos
        renderer = gtk.CellRendererText()
        renderer.set_data("column", COLUMN_SIZE)
        column = gtk.TreeViewColumn("#Photos", renderer, text=COLUMN_SIZE)
        # column.set_resizable(True);
        columns.append(column)

        for column in columns:
            # column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
            column.set_resizable(True)
            treeview.append_column(column)


    def new_cb(self, b, treeview):
        debug.log("treeview=%s" % treeview)
        self.add_album("", "", "", 0)
        self.button_new.set_sensitive(False)
        self.button_add.set_sensitive(True)
        self.statusbar.set_text("Fill Name & Summary and click <+Add>")
        gobject.idle_add(self.scroll_end)
        model = treeview.get_model()
        self.treeview.set_cursor(len(model) - 1, 
                                 treeview.get_column(COLUMN_NAME), True)


    def scroll_end(self):
        adj = self.scrolled_window.get_vadjustment()
        adj.set_value(adj.get_upper() - adj.get_page_size()) # Scroll to end
        path = self.treeview.get_path_at_pos(20, 50)
        # sys.stdout.write("path=%s\n" % str(path))


    def add_cb(self, b, treeview):
        debug.log("treeview=%s" % treeview)
        model = treeview.get_model()
        name = model[-1][COLUMN_NAME]
        summary = model[-1][COLUMN_SUMMARY]
        if self.name_ok_at(len(model)-1, name):
            self.statusbar.set_text("Adding album '%s'" % name)
            if self.do_add(name, summary):
                self.button_new.set_sensitive(True)
                self.button_add.set_sensitive(False)



    def remove_cb(self, b, treeview):
        debug.log("treeview=%s" % treeview)
        selection = treeview.get_selection()
        model, iter = selection.get_selected()

        album_id = "";  n = -1
        if iter:
            e = model.get_path(iter)
            debug.log("Selected e=%s" % str(e))
            album_name = model.get_value(iter, COLUMN_NAME)
            album_id = model.get_value(iter, COLUMN_ID)
            n = model.get_value(iter, COLUMN_SIZE)
            debug.log("id=%s, n=%d" % (album_id, n))
            if album_id == "":
                self.statusbar.set_text("No real album id to remove")
                self.refresh()
            elif n != 0:
                self.statusbar.set_text("Will not remove non empty album")
            else:
                self.statusbar.set_text("Removing '%s' id=%s" %
                                        (album_name, album_id))
                if self.do_remove(album_id):
                    debug.log("Album '%s' removed" % album_name)
                    model.remove(iter)
                    self.refresh()


    def refresh_cb(self, b):
        debug.log("")
        self.refresh()


    def refresh(self):
        self.treeview.get_model().clear()
        self.populate()
        self.button_new.set_sensitive(True)
        self.button_add.set_sensitive(False)


    def editing_started(self, cellrenderer, editable, path):
        debug.log("")
        self.statusbar.set_text("Hit <Enter> when done editing")


    def cell_edited(self, cell, path_string, new_text):
        debug.log("cell=%s, path_string=%s, new_text=%s" %
                  (cell, path_string, new_text))
        self.statusbar.set_text("")
        model = self.treeview.get_model()
        iter = model.get_iter_from_string(path_string)
        path = model.get_path(iter)[0]
        column = cell.get_data("column")
        ok = True
        if path < len(model) - 1:
            model_row = model[path]
            album_id = model_row[COLUMN_ID]
            if column == COLUMN_NAME:
                ok = self.name_ok_at(path, new_text)
                ok = ok and self.do_name(album_id, new_text)
            else:
                ok = self.do_summary(album_id, new_text)
        if ok:
            model.set(iter, column, new_text)


    def name_ok_at(self, at, name_at):
        model = self.treeview.get_model()
        debug.log("at=%s" % at)
        ok = True
        if string.strip(name_at) == "":
            self.statusbar.set_text("Album name must not be empty")
        else:
            i = 0
            # check uniqueness
            while ok and i < len(model):
                ok = (i == at) or name_at != model[i][COLUMN_NAME]
                i += 1
            if not ok:
                self.statusbar.set_text("Album name should be unique")
        return ok


    # Dummy base-methods
    def do_add(self, name, summary):
        return True

    def do_remove(self, album_id):
        debug.log("album_id=%s" % album_id)
        return True

    def do_name(self, album_id, name):
        return True

    def do_summary(self, album_id, summary):
        return True

    def populate(self):
        pass


class AlbumsEditor(_ListEditor):


    def __init__(self, picasa_editor):
        self.ped = picasa_editor
        _ListEditor.__init__(self, self.ped.uimain.topwin)
        self.refresh()


    def do_add(self, name, summary):
        self.gupicasa().album_add(name, summary)
        return True


    def do_remove(self, album_id):
        return self.gupicasa().album_del(album_id)


    def do_name(self, album_id, name):
        return self.gupicasa().album_rename(album_id, name)


    def do_summary(self, album_id, summary):
        debug.log("id=%s, summary=%s" % (album_id, summary))
        return self.gupicasa().album_summary(album_id, summary)


    def populate(self):
        debug.log("")
        gupicasa = self.gupicasa()
        albums_info = gupicasa.get_albums_info()
        for a in albums_info:
            debug.log("id=%s, name=%s summary=%s n=%d" %
                      (a.id, a.name, a.summary, a.n))
            self.add_album(a.id, a.name, a.summary, a.n)


    def gupicasa(self):
        return self.ped.uimain.parent


if __name__ == '__main__':

    class DB:

        def __init__(self):
            self.nextid = 0
            self.es = []
            for n in range(30):
                sz = 0 if n == 7 else 100+n
                self.add("Name %d" % n, "Summary %d" % n, sz)

        def add(self, name, summary, sz):
            self.es.append(("Id%d" % self.nextid, name, summary, sz))
            self.nextid += 1

        def remove(self, album_id):
            debug.log("album_id=%s" % album_id)
            es = self.es
            ei = len(es) - 1
            while ei >= 0 and es[ei][0] != album_id:
                ei -= 1
            if ei >= 0:
                debug.log("ei=%d" % ei)
                self.es = es[:ei] + es[ei + 1:]


    class TestListEditor(_ListEditor):

        def __init__(self, parent, db):
            _ListEditor.__init__(self, parent)
            self.db = db

        def do_add(self, name, summary):
            debug.log("name=%s, summary=%s" % (name, summary))
            ok = name.find('z') < 0
            if ok:
                self.db.add(name, summary, 0)
            return ok

        def do_remove(self, album_id):
            ok = not album_id[0] in "37"
            debug.log("album_id=%s, ok=%d" % (album_id, ok))
            if ok:
                self.db.remove(album_id)
            return ok

        def populate(self):
            for e in self.db.es:
                self.add_album(e[0], e[1], e[2], e[3])


    def ae_trigger(w, topwin, db):
        ae = TestListEditor(topwin, db)
        # ae.show_all()
        ae.refresh()
        album_id = ae.select()
        sys.stdout.write("album_id=%s\n" % album_id)


    import sys
    debug.log("Hello")
    db = DB()
    topwin = gtk.Window()
    topwin.set_size_request(360, 60)
    topwin.set_title("Test: Albums Editor")
    topwin.connect('delete-event', gtk.main_quit)
    vbox = gtk.VBox()
    b = gtk.Button("Test Albums Editor...")
    b.connect('clicked', ae_trigger, topwin, db)
    vbox.pack_start(b, padding=3)
    topwin.add(vbox)
    topwin.show_all()
    gtk.main()
    debug.log("Bye")
    sys.exit(0)
